$TITLE ('RTX-51 SYSTEM CLOCK')
$SYMBOLS
$NOXREF
$NOCOND
$NOMOD51
$NORB
$PAGELENGTH(80) PAGEWIDTH(110)
;************************************************************************
;*                                                                      *
;*    R T X - 5 1  :   SYSTEM CLOCK                                     *
;*                                                                      *
;*----------------------------------------------------------------------*
;*                                                                      *
;*    Filename     :   RTXCLK.A51                                       *
;*    Language     :   Keil A-51                                        *
;*    Dev. system  :   Keil uVision2                                    *
;*    Targetsystem :   Any system based upon 8051 up                    *
;*                                                                      *
;*    Purpose      :   Contains the system clock interrupt handler      *
;*                     and the initialisation system call.              *
;*                                                                      *
;*----------------------------------------------------------------------*
;* Rev. |  Released   | Programmer    | Comments                        *
;*----------------------------------------------------------------------*
;*  0.1 |  16.1.1991  | E. Glatz      | Changes for V3.18               *
;*  0.2 |   8.3.1991  | Th. Fischler  | Changes for V4.0                *
;*      |  10.5.1991  |               | P2-addressing eliminated        *
;*      |  18.5.1991  |               | ISR-function handling included  *
;*      |  19.9.1991  |               | Handling of the Supervisor-mode *
;*      |             |               | flag                            *
;*      | 18.11.1991  | Th. Fischler  | Store hanging CLK-INT's         *
;*      | 29.11.1991  |               | Clear the Wait-TMO state bit    *
;*      |             |               | if task has timeout             *
;*      | 21.4.1992   |               | Handle Clock-Reload overflow    *
;*      | 28.4.1992   |               | Disable all Int's while clock   *
;*      |             |               | reload / FERAG adaptions        *
;*      |  4.06.1992  |               | RTXINS.INC converted to proc.   *
;*      |  9.11.1992  | Th. Fischler  | os_set_slice returnvalue        *
;*      |             |               | corrected                       *
;* 5.00 | 12.10.1994  | E. Glatz      | SEM_DEQUEUE added, store wakeup *
;*      | 10.04.1996  |               | Global int disable around FERAG *
;* 5.10 | 19.04.1996  |               | Use ?RTX_TCON,etc. for timer's 2*
;* 7.00 | 13.11.2001  | T. Mueller    | Release 7.00                    *
;************************************************************************
;*    Copyright 1991 .. 2001 METTLER  &  FUCHS  AG,  CH-8953 Dietikon   *
;************************************************************************

$INCLUDE (RTXDEBUG.INC)
$INCLUDE (RTXIMASK.INC)
$INCLUDE (RTXGETPR.INC)

;*----------------------------------------------------------------------*
;*      DATA DEFINITIONS FOR FERAG VERSION
;*----------------------------------------------------------------------*

; ********* FERAG
$IF (FERAG)
   PUBLIC   COUNT, COUNTHI, COUNTLO

   ?RTX?FERAG_COUNTER?RTXCLK  SEGMENT DATA BITADDRESSABLE
                              RSEG ?RTX?FERAG_COUNTER?RTXCLK
      COUNT:
      COUNTHI:    DS 1
      COUNTLO:    DS 1
$ENDIF
; ********* FERAG



;*----------------------------------------------------------------------*
;*      I M P O R T S
;*----------------------------------------------------------------------*

$INCLUDE (RTXCONST.INC)
$INCLUDE (RTXEXTRN.INC)

;        FROM RTXINT
EXTRN    CODE     (?RTX_RESET_I_F_F)

;        FROM REDISPATCH
EXTRN    CODE     (?RTX_REDISPATCH)

;        FROM RTXQUOP
EXTRN    CODE     (?RTX_NFL_DEQUEUE, ?RTX_INTSIG_DEQUEUE)
EXTRN    CODE     (?RTX_MSG_DEQUEUE, ?RTX_SEM_DEQUEUE)

;        FROM RTXIHAND
EXTRN    CODE     (?RTX_HANDLE_ISR_SEND_SIG)
EXTRN    CODE     (?RTX_HANDLE_ISR_SEND_MES)
EXTRN    CODE     (?RTX_HANDLE_NF_CHECK_REQ)

;        FROM RTXCONF
EXTRN    DATA     (?RTX_TLOW, ?RTX_THIGH, ?RTX_TMOD, ?RTX_TCON)
EXTRN    BIT      (?RTX_TFLAG, ?RTX_TCONTROL)
EXTRN    NUMBER   (?RTX_TMOD_AND_MASK, ?RTX_TMOD_OR_MASK)
EXTRN    NUMBER   (?RTX_TCON_AND_MASK, ?RTX_TCON_OR_MASK)

;        FROM RTXINS
EXTRN    CODE  (?RTX_INSERT_RDY_PRIO)


;*----------------------------------------------------------------------*
;*      E X P O R T S
;*----------------------------------------------------------------------*

PUBLIC  ?RTX_SYSCLK_INTHNDLR
PUBLIC  _os_set_slice


;*----------------------------------------------------------------------*
;*      M A C R O S
;*----------------------------------------------------------------------*
;       The following Macros contents the HW-specific part of the
;       System-Clock handler
;

;*----------------------------------------------------------------------*
;*      MACRO : SYSCLK_RELOAD
;*----------------------------------------------------------------------*
;*      Reload system clock timer.
;*      Compensate the time needed for the System-Clock routine and for
;*      Fast-Tasks.
;*----------------------------------------------------------------------*
;*      Input:   - SYS_TICK holds reload value
;*      Output:  - THIGH/TLOW new set
;*               - ACC and DPTR changed
;*----------------------------------------------------------------------*

SYSCLK_RELOAD  MACRO
               LOCAL ENDL
               GLOBAL_INT_DISABLE
               CLR   ?RTX_TCONTROL
               MOV   DPL, #LOW(?RTX_SYS_TICK)
               MOV   DPH, #HIGH(?RTX_SYS_TICK)
               INC   DPL                        ; Get low byte first
               MOVX  A, @DPTR
               ADD   A, ?RTX_TLOW
               MOV   ?RTX_TLOW, A
               DEC   DPL
               MOVX  A, @DPTR                   ; Get high byte
               ADDC  A, ?RTX_THIGH
               MOV   ?RTX_THIGH, A
               JNC   ENDL                       ; Check if compensate-overflow
               ; Compensate overflow. Set the timer to -50 for immediate
               ; Clock-INT
               MOV   ?RTX_THIGH, #0FFH
               MOV   ?RTX_TLOW, #0CDH
ENDL:          GLOBAL_INT_ENABLE
               SETB  ?RTX_TCONTROL              ; Enable counting
               ENDM


;*----------------------------------------------------------------------*
;*      MACRO : SYSCLK_INIT
;*----------------------------------------------------------------------*
;*      Initialise system clock timer.
;*      Use internal timer 0 as 16 bit timer.
;*----------------------------------------------------------------------*
;*      Input:   - Get count values from system var. 'SYS_TICK'
;*
;*      Output:  - 
;*----------------------------------------------------------------------*

SYSCLK_INIT    MACRO
               CLR   ?RTX_TCONTROL              ; Stop timer 0
               CLR   ?RTX_TFLAG                 ; Clear int. request
               MOV   DPH, #HIGH(?RTX_SYS_TICK)  ; Get count values
               MOV   DPL, #LOW(?RTX_SYS_TICK)
               MOVX  A, @DPTR
               MOV   ?RTX_THIGH, A              ; Load counters
               INC   DPL
               MOVX  A, @DPTR
               MOV   ?RTX_TLOW, A
               ;
               MOV   A, ?RTX_TCON               ; Set initial values
               ANL   A, #?RTX_TCON_AND_MASK     ; for TCON register
               ORL   A, #?RTX_TCON_OR_MASK      ; (if required)
               MOV   ?RTX_TCON, A
               ;
               MOV   A, ?RTX_TMOD
               ANL   A, #?RTX_TMOD_AND_MASK     ; Use timer 0 as 16
               ORL   A, #?RTX_TMOD_OR_MASK      ; bit timer
               MOV   ?RTX_TMOD, A
               ;
               SETB  ?RTX_TCONTROL              ; Enable counting
               ENDM



;*----------------------------------------------------------------------*
;*      P R O C E D U R E S
;*----------------------------------------------------------------------*

;*----------------------------------------------------------------------*
;*      R T X _ S Y S C L K _ I N T H D L R
;*----------------------------------------------------------------------*
;*      Systemclock interrupthandler. Executed upon each systemclock
;*      interrupt.
;*      This handler may be interrupted by fast tasks (=driver tasks), but may
;*      itself not interrupt a fast task. It interrupts standard tasks 
;*      (=non driver tasks).
;*
;*      On entry:       No registers saved.
;*      On exit:        All used registers are restored to their
;*                      previous values.
;*
;*      Uses:           10 bytes of standard task stack
;*----------------------------------------------------------------------*
;*      Input:   - 
;*      Output:  - 
;*----------------------------------------------------------------------*

?RTX?SYSCLK_INTHNDLR?RTXCLK  SEGMENT CODE
                             RSEG    ?RTX?SYSCLK_INTHNDLR?RTXCLK

?RTX_SYSCLK_INTHNDLR:
               ; Check if already in the system-clock handler
               JNB   ?RTX_SYSCLK_ISR, ENTRY_OK
               SETB  ?RTX_TFLAG                 ; re-activate overflow-INT
               RETI

ENTRY_OK:      DBG_CLKINT_ENTRY
               GLOBAL_INT_DISABLE
               SETB  ?RTX_SYSCLK_ISR
               GLOBAL_INT_ENABLE

               DBG_BUSY
               RTX_EXCLUDE_INT
               ; Reset H/W int. prio. F/F
               CALL ?RTX_RESET_I_F_F

               ; If previously idle, then set up system clock task id
               JB    ?RTX_PROCESSOR_ALLOCATED, PA
               MOV   ?RTX_RUNNING_TID, #SYSCLK_TID
               ; Set flag for system clock interrupt handler operation

PA:            ; Save PSW, ACC, R0, DPTR and SV-Flag
               PUSH  PSW
               PUSH  ACC
               MOV   A, R0
               PUSH  ACC
               PUSH  DPH
               PUSH  DPL
               MOV   C, ?RTX_SUPERVISOR_MODE
               PUSH  PSW
               JB    ?RTX_SUPERVISOR_MODE, NOCLR ; Init flag for disp. req.
               CLR   ?RTX_REQ_REDISPATCH

NOCLR:         ; Test if check for timeout tasks needed
               MOV   A, ?RTX_THIGH
               CLR   C
               SUBB  A, #HIGH(UNUSED_CLK_PART)
               JC    TIMEOUT_CHECK
               JMP   ISR_LIFO_CHECK

               ; Incr. system clock count
TIMEOUT_CHECK: INC   ?RTX_SYSCLK_COUNT
               MOV   A, ?RTX_SYSCLK_COUNT
               CJNE  A, #0FFH, NO_WRAP
               MOV   ?RTX_SYSCLK_COUNT, #0      ; Value 0FFH is reserved !
               $IF (DBG = 03H)
                  INC   ?RTX_SYSCLK_COUNTHI     ; For time logging
               $ENDIF
NO_WRAP:       
; ********* FERAG
               $IF (FERAG)
                  GLOBAL_INT_DISABLE
                  INC   COUNTLO
                  MOV   A, COUNTLO
                  JNZ   NO_INCH
                  INC   COUNTHI
NO_INCH:          GLOBAL_INT_ENABLE
               $ENDIF
; ********* FERAG

               ; SV-mode must be on before allowing fast task interrupts!
               SETB  ?RTX_SUPERVISOR_MODE
                                                
               RTX_ALLOW_DRV_INT
               ; Set up DPTR as pointer to delay list
               MOV   DPL, #LOW(?RTX_DELAY_LIST_TID)
CONT:          RTX_EXCLUDE_INT
               MOV   DPH, #HIGH(?RTX_DELAY_LIST_TID)
               ; Loop until all entries of delay list are checked for
               ; timeout (start at high end of table and go to low end)
CONTINUE:      MOV   A, DPL
               CJNE  A, #LOW(?RTX_DELAY_LIST_CLK), AGAIN
               JMP   ROUND_ROBIN_CHECK
               ; Check for timeout
AGAIN:         DEC   DPL                        ; (current count=timeout count)
               MOVX  A, @DPTR
               CJNE  A, ?RTX_SYSCLK_COUNT, CONTINUE ; Jump if no timeout
               ; Task with timeout found
               MOV   A, #0FFH                   ; delay_list_clk[task no]=0FFH
               MOVX  @DPTR, A                   ; (0FFH means 'empty')
               ; Get task id from delay_list_tid[task no]
               MOV   ?RTX_TMP1, R1              ; Save R1 (used by NFL_DEQUEUE)
               MOV   ?RTX_TMP2, DPL             ; Save DPL
               MOV   A, DPL
               ; Get task id from delay list
               ADD   A, #TASK_COUNT             ; Offset between delay_list
               MOV   DPL, A                     ; _clk and delay_list_tid
               MOVX  A, @DPTR
               MOV   ?RTX_TMP0, A               ; Save task id in ?RTX_TMP0
               ; Set up ptr to state_table[task no]
               ANL   A, #01FH
               RL    A
               RL    A
               ADD   A, #LOW(?RTX_STATE_TABLE)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_STATE_TABLE) ; DPTR->state_table[task no]
               ; Clear wait-signal Bit in state-table
               MOVX  A, @DPTR
               ANL   A, #0F7H
               MOVX  @DPTR, A
               ; Dequeue from nonfull wait lst
               ; ?RTX_TMP0 contains task id
               CALL  ?RTX_NFL_DEQUEUE
               ; If it was queued for non full then it can not be queued for
               ; msg and/or sig and/or int
               JZ    DEQ_DONE
                                                ; DPTR, ?RTX_TMP0 preserved
               ; Dequeue from int/sig lists
               CALL  ?RTX_INTSIG_DEQUEUE
               ; DPTR, ?RTX_TMP0 preserved
               ; Dequeue from msg list
               CALL  ?RTX_MSG_DEQUEUE
               JZ    DEQ_DONE                   ; Eval ret code if deq done
                                                ; DPTR preserved if no deq done
                                                ; ?RTX_TMP0 preserved
               CALL  ?RTX_SEM_DEQUEUE           
                                                ; ?RTX_TMP0 preserved
DEQ_DONE:      ; Store wake-up time
               MOV   A, ?RTX_TMP0
               ANL   A, #01FH 
               ADD   A, #LOW(?RTX_INTERVAL_LIST)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_INTERVAL_LIST) 
               MOV   A, ?RTX_SYSCLK_COUNT
               MOVX  @DPTR, A

               ; Insert task in ready list
               MOV   A, ?RTX_TMP0
               CALL  ?RTX_INSERT_RDY_PRIO
               ; Set request for dispatch
               SETB  ?RTX_REQ_REDISPATCH
               MOV   R1, ?RTX_TMP1              ; Restore R1

               ; Store return status in task context
               JB    ?RTX_TMP0.4, DRV_CONTXT    ; Fast and standard tasks must
                                                ; be handled differently
               ; Store in standard task context
               MOV   A, ?RTX_TMP0
               ANL   A, #0FH
               MOV   R0, A
               MOV   A, #LOW(?RTX_KNTXT_PTR_TABLE)
               ADD   A, R0
               ADD   A, R0
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_KNTXT_PTR_TABLE)
               MOVX  A, @DPTR
               MOV   R0, A
               INC   DPL
               MOVX  A, @DPTR
               MOV   DPH, R0
               MOV   DPL, A

               MOV   A, #TMO_EVENT
               INC   DPL
               MOVX  @DPTR, A                   ; Store return status to R7
               MOV   DPL, ?RTX_TMP2             ; Restore DPL
               RTX_ALLOW_DRV_INT
               JMP   CONT
                                                
DRV_CONTXT:    ; Store in fast task context
               JB    ?RTX_TMP0.1, DRV3
               JB    ?RTX_TMP0.0, DRV2

DRV1:          MOV   RB1R7, #TMO_EVENT
               MOV   DPL, ?RTX_TMP2             ; Restore DPL
               RTX_ALLOW_DRV_INT
               JMP   CONT

DRV2:          MOV   RB2R7, #TMO_EVENT
               MOV   DPL, ?RTX_TMP2             ; Restore DPL
               RTX_ALLOW_DRV_INT
               JMP   CONT

DRV3:          MOV   RB3R7, #TMO_EVENT
               MOV   DPL, ?RTX_TMP2             ; Restore DPL
               RTX_ALLOW_DRV_INT
               JMP   CONT


ROUND_ROBIN_CHECK:
               RTX_EXCLUDE_INT
               MOV   A, #?RTX_TIMESHARING
               CJNE  A, #1, END_CHECK
               JB    ?RTX_TS_DELAY, NO_RR       ; check if r-robin allowed
               SETB  ?RTX_ROUND_ROBIN_REQ
               SETB  ?RTX_REQ_REDISPATCH
               JMP   END_CHECK
NO_RR:         SETB  ?RTX_TS_REQ                ; when no r-robin allowed,
                                                ; set the C-51 request flag
END_CHECK:     ; Reload sys.clk. timer
               SYSCLK_RELOAD


ISR_LIFO_CHECK:
               ; SV-mode must be on before allowing fast task interrupts!
               SETB  ?RTX_SUPERVISOR_MODE
               RTX_ALLOW_DRV_INT
               RTX_EXCLUDE_INT                  ; Fast task interrupt window
               GLOBAL_INT_DISABLE
               MOV   A, ?RTX_ACT_LIFO_EL
               JZ    SYSCLK_DONE
               CLR   C
               SUBB  A, #3
               MOV   ?RTX_ACT_LIFO_EL, A
               ADD   A, #LOW(?RTX_ISR_LIFO)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_ISR_LIFO)
               MOVX  A, @DPTR
               MOV   ?RTX_TMP3, R1              ; save R1
               MOV   ?RTX_TMP4, R2              ; save R2
               ; Check the requested command
               CJNE  A, #ISR_SEND_SIG_CMD, NF_CHECK
SEND_SIG:      INC   DPL
               INC   DPL
               MOVX  A, @DPTR
               MOV   R0, A                      ; R0 holds task-number
               GLOBAL_INT_ENABLE
               CALL  ?RTX_HANDLE_ISR_SEND_SIG
               JMP   END_LIFO_CHECK
NF_CHECK:      CJNE  A, #ISR_NF_CHK_CMD, REQ_RR
               INC   DPL
               INC   DPL
               MOVX  A, @DPTR
               MOV   R0, A                      ; R0 holds Mailbox-number
               GLOBAL_INT_ENABLE
               CALL  ?RTX_HANDLE_NF_CHECK_REQ
               JMP   END_LIFO_CHECK
REQ_RR:        CJNE  A, #REQ_ROUND_R_CMD, SEND_MES
               SETB  ?RTX_ROUND_ROBIN_REQ
               SETB  ?RTX_REQ_REDISPATCH
               GLOBAL_INT_ENABLE
               JMP   END_LIFO_CHECK
SEND_MES:      MOV   R0, A                      ; R0 holds Mailbox-number
               INC   DPL
               MOVX  A, @DPTR
               MOV   R1, A                      ; R1 holds HIGH(message)
               INC   DPL
               MOVX  A, @DPTR
               MOV   R2, A                      ; R2 holds LOW(message)
               GLOBAL_INT_ENABLE
               CALL  ?RTX_HANDLE_ISR_SEND_MES

END_LIFO_CHECK:
               MOV   R1, ?RTX_TMP3              ; Restore R1
               MOV   R2, ?RTX_TMP4              ; Restore R2
               JMP   ISR_LIFO_CHECK


SYSCLK_DONE:   POP   PSW                        ; Restore SV-Flag, DPTR,
               MOV   ?RTX_SUPERVISOR_MODE, C    ; R0, ACC, PSW
               POP   DPL                        
               POP   DPH
               POP   ACC
               MOV   R0, A
               POP   ACC
               POP   PSW

               JNB   ?RTX_REQ_REDISPATCH, NO_REQ ; Check if redisp. request
               SETB  ?RTX_FULL_CONTEXT          ; Set context type
NO_REQ:
               JNB   ?RTX_PROCESSOR_ALLOCATED, RQ_CHK ; Check if proc. allocated
SV_CHK:        JB    ?RTX_SUPERVISOR_MODE, SVEXIT ; Synchronize w. dispatcher
RQ_CHK:        JB    ?RTX_REQ_REDISPATCH, DISP
               ; Return to standard task (=non driver task) executing user
               ; code or to idle mode
EXIT:          CLR   ?RTX_SYSCLK_ISR
               JB    ?RTX_PROCESSOR_ALLOCATED, EXIT1
               MOV   ?RTX_RUNNING_TID, #NIL_TID
EXIT1:         DBG_CLKINT_EXIT
               DBG_SYS_EXIT
               RTX_ALLOW_INT
               GLOBAL_INT_ENABLE
               RET                              ; I_F_F already reset
               ; Redispatch
DISP:          CLR   ?RTX_SYSCLK_ISR
               JB    ?RTX_PROCESSOR_ALLOCATED, DISP1
               MOV   ?RTX_RUNNING_TID, #NIL_TID
DISP1:         DBG_CLKINT_EXIT
               GLOBAL_INT_ENABLE
               JMP   ?RTX_REDISPATCH

               ; Return to standard task (=non driver task) executing
               ; system code (do not allow standard task interrupts !)
SVEXIT:        CLR   ?RTX_SYSCLK_ISR
               JB    ?RTX_PROCESSOR_ALLOCATED, SVEXIT1
               MOV   ?RTX_RUNNING_TID, #NIL_TID
SVEXIT1:       DBG_CLKINT_EXIT
               RTX_ALLOW_DRV_INT
               GLOBAL_INT_ENABLE
               RET




;*----------------------------------------------------------------------*
;*      O S _ S E T _ S L I C E
;*----------------------------------------------------------------------*
;*      Set the system-clock intervall.
;*----------------------------------------------------------------------*
;*      Input:   - R6 : HIGH (time slice)
;*               - R7 : LOW (time slice)
;*
;*      Output:  - R7 :  0 -> Ok
;*                      -1 -> time slice must be between 1000 and 40000
;*----------------------------------------------------------------------*

?RTX?_os_set_slice?RTXCLK  SEGMENT CODE
                              RSEG    ?RTX?_os_set_slice?RTXCLK

_os_set_slice:
                DBG_SYS_ENTRY
                RTX_EXCLUDE_INT
                ; Check the time slice
                CLR     C
                MOV     A,R7
                SUBB    A,#LOW(CLK_SLICE_MIN)
                MOV     A,R6
                SUBB    A,#HIGH(CLK_SLICE_MIN)
                JC      OSS_1
                SETB    C
                MOV     A,R7
                SUBB    A,#LOW(CLK_SLICE_MAX)
                MOV     A,R6
                SUBB    A,#HIGH(CLK_SLICE_MAX)
                JC      OSS_2

OSS_1:          MOV     R7,#NOT_OK              ; invalid time slice
                DBG_SYS_EXIT
                RTX_ALLOW_INT
                RET

OSS_2:          ; build the 2's complement
                MOV     A, R7
                CPL     A
                ADD     A, #01H
                MOV     R7, A
                MOV     A, R6
                CPL     A
                ADDC    A, #00H
                MOV     R6, A
                ; store the value in the variable sys_tick
                MOV     DPH, #HIGH(?RTX_SYS_TICK)
                MOV     DPL, #LOW(?RTX_SYS_TICK)
                MOV     A, R6                   ; Store system tick 
                MOVX    @DPTR, A
                MOV     A, R7
                INC     DPL
                MOVX    @DPTR, A
;               Call h/w clock init with system tick in SYS_TICK
                SYSCLK_INIT
                MOV     R7, #OK
                DBG_SYS_EXIT
                RTX_ALLOW_INT
                RET
;
;   END OF MODULE
;
        END
